package cn.demoncat.util.lang;

import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.StringUtils;
import org.springframework.expression.Expression;
import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import cn.demoncat.util.lang.constant.StringConstant;

/**
 * EL表达式工具
 * 
 * @author 延晓磊
 *
 * @since 2019年1月9日
 */
public final class ElUtil {
 
	/**
	 * 解析 SpringEL 表达式
	 * <pre>
	 * # SpEL语法
	 * 
	 * 获取value.id属性：#{id}
	 * 获取value.user.name：#{user.name}
	 * 
	 * 实例方法value.getId()：#{getId()}
	 * 实例方法value.id.length()：#{id.length()}
	 * 静态方法User.get(a,b)：#{T(cn.demoncat.User).get(123,456)}
	 * 静态属性IpUtil.LOCAL_IP：#{T(cn.demoncat..IpUtil).LOCAL_IP}
	 * 
	 * 算术运算：#{1+2*3-4}
	 * 比较运算：#{10 eq 10}
	 * 逻辑运算：#{true and false or !false || not true}
	 * 三目运算：#{(10>3)?'真':'假'}"
	 * 
	 * 拼接字符串："xx#{id}xx"
	 * 拼接字符串："#{id}#{user.name}"
	 * 字符串拼接："#{1+'个'+'月后'}"
	 * 
	 * </pre>
	 * @param expression	表达式：你好#{user.name}，验证码是#{code}
	 * @param value			数据(Obj类型 = 读取对象的Field或Getter，支持多层级；Map类型 = 读取key，支持单层级)
	 * 
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年1月9日
	 */
	public static String parse(String expression, Object value) {
		if (StringUtils.isBlank(expression) || !expression.contains(StringConstant.LEFT_SEL)) {
			return expression;
		}
		// 解析
		if (value == null) {
			// 无数据，直接解析：解析器 > 读取结果
			return getSpelExpression(expression).getValue(String.class);
		}else if (value instanceof Map) {
			// Map数据，先解析数据，再解析表达式
			expression = parseSel(expression, JsonUtil.parseMapSs(JsonUtil.toStr(value)));
			if (expression.contains(StringConstant.LEFT_SEL)) {
				return getSpelExpression(expression).getValue(String.class);
			}else {
				return expression;
			}
		}else {
			// Obj数据，注入解析：解析器 > 注入数据 > 读取结果
			return getSpelExpression(expression).getValue(new StandardEvaluationContext(value), String.class);
		}
	}
	
	/**
	 * 获取SpEL表达式解析器
	 * 
	 * @param expression
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年4月18日
	 */
	public static Expression getSpelExpression(String expression) {
		// 解析器 > 解析表达式
		return new SpelExpressionParser().parseExpression(expression, ParserContext.TEMPLATE_EXPRESSION);
	}
	
	/**
	 * 解析NL表达式
	 * 
	 * @param expression	NL表达式：你好{1}，验证码是{2}
	 * @param value			动态数据，对应NL的占位符数
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年1月9日
	 */
	public static String parseNl(String expression, String... value) {
		// 没有占位符
		if (value == null || value.length == 0 || StringUtils.isBlank(expression) || !expression.contains(StringConstant.LEFT_BRACE)) {
			return expression;
		}
		// 替换占位符
		String[] searchs = new String[value.length]; 
		for (int i = 0; i < value.length; i++) {
			searchs[i] = StringConstant.LEFT_BRACE + (i+1) + StringConstant.RIGHT_BRACE;
		}
		return StringUtils.replaceEach(expression, searchs, value);
	}
	
	/**
	 * 解析BL表达式
	 * 
	 * @param expression	BL表达式：你好{user}，验证码是{code}
	 * @param value			动态数据，对应BL的占位符key
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年1月9日
	 */
	public static String parseBl(String expression, Map<String, String> value) {
		// 没有占位符
		if (value == null || value.isEmpty() || StringUtils.isBlank(expression) || !expression.contains(StringConstant.LEFT_BRACE)) {
			return expression;
		}
		// 替换占位符
		String[] searchs = new String[value.size()]; 
		String[] values = new String[value.size()]; 
		int i = 0;
		for (Entry<String, String> entry : value.entrySet()) {
			searchs[i] = StringConstant.LEFT_BRACE + entry.getKey() + StringConstant.RIGHT_BRACE;
			values[i] = entry.getValue();
			i++;
		}
		return StringUtils.replaceEach(expression, searchs, values);
	}
	
	/**
	 * 解析EL表达式
	 * 
	 * @param expression	EL表达式：你好${user}，验证码是${code}
	 * @param value			动态数据，对应EL的占位符key
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年1月9日
	 */
	public static String parseEl(String expression, Map<String, String> value) {
		// 没有占位符
		if (value == null || value.isEmpty() || StringUtils.isBlank(expression) || !expression.contains(StringConstant.LEFT_EL)) {
			return expression;
		}
		// 替换占位符
		String[] searchs = new String[value.size()]; 
		String[] values = new String[value.size()]; 
		int i = 0;
		for (Entry<String, String> entry : value.entrySet()) {
			searchs[i] = StringConstant.LEFT_EL + entry.getKey() + StringConstant.RIGHT_EL;
			values[i] = entry.getValue();
			i++;
		}
		return StringUtils.replaceEach(expression, searchs, values);
	}
	
	/**
	 * 解析SEL表达式
	 * 
	 * @param expression	SEL表达式：你好#{user}，验证码是#{code}
	 * @param value			动态数据，对应SEL的占位符key
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年1月9日
	 */
	public static String parseSel(String expression, Map<String, String> value) {
		// 没有占位符
		if (value == null || value.isEmpty() || StringUtils.isBlank(expression) || !expression.contains(StringConstant.LEFT_SEL)) {
			return expression;
		}
		// 替换占位符
		String[] searchs = new String[value.size()]; 
		String[] values = new String[value.size()]; 
		int i = 0;
		for (Entry<String, String> entry : value.entrySet()) {
			searchs[i] = StringConstant.LEFT_SEL + entry.getKey() + StringConstant.RIGHT_SEL;
			values[i] = entry.getValue();
			i++;
		}
		return StringUtils.replaceEach(expression, searchs, values);
	}
	
	/**
	 * 解析LL表达式
	 * 
	 * @param expression	LL表达式：你好{}，验证码是{}
	 * @param value			动态数据，对应LL的占位符数
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年1月9日
	 */
	public static String parseLl(String expression, Object... value) {
		return StringUtil.logFormat(expression, value);
	}

	/**
	 * 解析VUE表达式
	 * 
	 * @param expression	VUE表达式：你好{{user}}，验证码是{{code}}
	 * @param value			动态数据，对应EL的占位符key
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年1月9日
	 */
	public static String parseVue(String expression, Map<String, String> value) {
		// 没有占位符
		if (value == null || value.isEmpty() || StringUtils.isBlank(expression) || !expression.contains(StringConstant.DOUBLE_LEFT_BRACE)) {
			return expression;
		}
		// 替换占位符
		String[] searchs = new String[value.size()]; 
		String[] values = new String[value.size()]; 
		int i = 0;
		for (Entry<String, String> entry : value.entrySet()) {
			searchs[i] = StringConstant.DOUBLE_LEFT_BRACE + entry.getKey() + StringConstant.DOUBLE_RIGHT_BRACE;
			values[i] = entry.getValue();
			i++;
		}
		return StringUtils.replaceEach(expression, searchs, values);
	}
}
